/**
 * @File name: board/linux/test_char_dev.c
 * @Synopsis:
 * @Author: xing.dai@aliyun.com
 * @Version: 0.0.1
 * @Date: 2018-08-27 19:28
 */

#include "includes.h"
#include "test_char_dev.h"


/**
 * @Synopsis  driver private data.
 */
typedef struct _test_dev_private_data {
    uint32 data1;
    uint32 data2;
    uint32 data3;
} test_dev_data_t;

device_t *test_dev;
test_dev_data_t test_dev_data;

static int test_dev_init(device_t *dev)
{
    show_info("%s: init.\n", test_dev->object.name);
    return 0;
}

static int test_dev_open(device_t *dev, uint32 oflag)
{
    show_info("%s: open.\n", test_dev->object.name);
    return 0;
}

static int test_dev_close(device_t *dev)
{
    show_info("%s: close.\n", test_dev->object.name);
    return 0;
}

static uint32 test_dev_read(device_t *dev, int32 pos, void *buffer, int32 size)
{
    test_dev_data_t *data = (test_dev_data_t *)test_dev->private;

    show_info("%s: read.\n", test_dev->object.name);
    dbg_yellow("%d-%d-%d\n", data->data1, data->data2, data->data3);
    return 0;
}

static uint32 test_dev_write(device_t *dev, int32 pos, void *buffer, int32 size)
{
    test_dev_data_t *data = (test_dev_data_t *)test_dev->private;
    data->data1 = 1;
    data->data2 = 2;
    data->data3 = 3;
    show_info("%s: write.\n", test_dev->object.name);

    return 0;
}

static int test_dev_control(device_t *dev, uint8 cmd, void *args)
{
    show_info("%s: control.\n", test_dev->object.name);
    return 0;
}


/**
 * @Synopsis
 *
 * @Param device
 * @Param name		a pointer to an ASCII string to provide a name to the task.
 * @Param flag
 * @Param data
 *
 * @Returns
 */
static int test_dev_register(device_t *device, char *name, uint32 flag, void *data)
{
    device->type = DEVICE_CLASS_CHAR;
    //strncpy(device->name, name, DEVICE_NAME_MAX_LEN - 1);
    device->rx_indicate = NULL;
    device->tx_complete = NULL;
    device->init = test_dev_init;
    device->open = test_dev_open;
    device->close = test_dev_close;
    device->read = test_dev_read;
    device->write = test_dev_write;
    device->control = test_dev_control;
    device->private = data;

    return device_register(device, name, flag);
}


/**
 * @Synopsis  init test char driver.
 *				1. Alloc device struct to point.
 *				2. Initial driver struct and register device to device_tree.
 * @Returns
 */
int test_dev_hw_init(void)
{
    char *dev_name = "test_char_dev";
    test_dev = (device_t *)smalloc(MEM_STATIC_DEVICE_ID);
    if (test_dev == NULL) {
        dbg0("Alloc %s failed.\n", dev_name);
        return -1;
    }

    if (test_dev_register(test_dev, dev_name, 0, (void *)&test_dev_data) != SUCC) {
        dbg0("Register %s failed.\n", dev_name);
        return -3;
    }

    return 0;
}

int test_char_driver(void)
{
    device_t *device;
    device_t *ttt;
    if (test_dev_hw_init() != 0) {
        return -1;
    }

    device = test_dev;
    device->init(device);
    device->open(device, 0x12);
    device->write(device, 123, NULL, 0);
    device->read(device, 123, NULL, 0);
    device->control(device, 123, NULL);
    device->close(device);
    ttt = list_entry(&device->init, device_t, init);
    dbg0("device: %p, ttt:%p.\n", device, ttt);
    dbg1("ele:%p off:%u.\n", &device->init, (unsigned long)(&((device_t *)0)->init));
    return 0;
}
